package us.wili.dev.netty.handler;

import com.alibaba.fastjson.JSON;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import us.wili.dev.dao.mapper.cache.GroupChatCache;
import us.wili.dev.exception.ErrorCode;
import us.wili.dev.model.entity.Game;
import us.wili.dev.model.entity.GroupChat;
import us.wili.dev.model.entity.User;
import us.wili.dev.netty.dao.cache.GameRoomCache;
import us.wili.dev.netty.model.*;
import us.wili.dev.netty.model.game.Player;
import us.wili.dev.netty.model.game.Room;
import us.wili.dev.netty.model.potodto.GameToRoom;
import us.wili.dev.netty.model.potodto.PlayerPoToDtoUtil;
import us.wili.dev.netty.model.req.GameRoomReq;
import us.wili.dev.netty.model.req.GroupChatReq;
import us.wili.dev.netty.model.rsp.RoomInfoRsp;
import us.wili.dev.netty.service.*;

import java.util.*;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class MessageEventHandler {

    private static final Logger logger = LoggerFactory.getLogger(MessageEventHandler.class);

    //会话集合
    private static final ConcurrentSkipListMap<String, ClientInfo> webSocketMap = new ConcurrentSkipListMap<>();

    //群组在线人数
    private static final ConcurrentSkipListMap<String, ConcurrentSkipListMap<String, ClientInfo>> groupOnlineMap = new ConcurrentSkipListMap<>();


    //静态变量，用来记录当前在线连接数。（原子类、线程安全）
    private static AtomicInteger onlineCount = new AtomicInteger(0);

    private final   SocketIOServer server;

    @Autowired
    private GroupChatCache groupChatCache;
    @Autowired
    private GameRoomCache gameRoomCache;

    @Autowired
    public MessageEventHandler(SocketIOServer server) {
        this.server = server;
    }

    @Autowired
    public RedisTemplate redisTemplate;


    @Autowired
    private NettyGroupMsgService groupMsgService;
    @Autowired
    private NettyGroupChatService groupChatService;
    @Autowired
    private NettyGroupClubService groupClubService;
    @Autowired
    private UserService userService;
    @Autowired
    private NettyRoomService roomService;

    /**
     * connect事件处理，当客户端发起连接时将调用
     *
     * @param client
     */
    @OnConnect
    public void onConnect(SocketIOClient client) {
        Long clientID = Long.parseLong(client.getHandshakeData().getSingleUrlParam("clientID"));
        logger.info("socket链接:" + clientID);
        UUID session = client.getSessionId();
        ClientInfo si = webSocketMap.get(clientID);
        //如果没有链接信息、则新建会话信息
        if (si == null) {
            si = new ClientInfo();
            si.setOnline(true);
            si.setClientId(clientID.toString());
            logger.info("socket 建立新连接、sessionId:" + session + "、clientId:" + clientID + "、当前连接数：" + onlineCount.incrementAndGet());
        }
        //更新设置客户端连接信息
        si.setLeastSignificantBits(session.getLeastSignificantBits());
        si.setMostSignificantBits(session.getMostSignificantBits());
        si.setLastConnectedTime(new Date());
        //将会话信息更新保存至集合
        webSocketMap.put(clientID.toString(), si);
        if (!StringUtils.isBlank(clientID.toString())) {
            join_group_online(clientID, si);
        }
    }


    /**
     * disconnect事件处理，当客户端断开连接时将调用
     *
     * @param client
     */
    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        String clientId = client.getHandshakeData().getSingleUrlParam("clientID");
        webSocketMap.remove(clientId);
        //下线将群聊在线集合中移除
        left_group_offline(Long.parseLong(clientId));
        //在线数减1
        logger.info("socket 断开连接、sessionId:" + client.getSessionId() + "、clientId:" + clientId + "、当前连接数：" + onlineCount.decrementAndGet());
    }

    /**
     * 消息接收入口，当接收到消息后，查找发送目标客户端，并且向该客户端发送消息，且给自己发送消息
     *
     * @param client
     * @param request
     * @param data
     */
    @OnEvent(value = "message_event")
    public void onEvent(SocketIOClient client, AckRequest request, RequestDto data) {
        RequestDto requestDto = null;
        GroupChatReq GroupReq = null;
        GameRoomReq gameReq = null;

        GameResponseDto gameResponseDto = new GameResponseDto();
        String clientID = client.getHandshakeData().getSingleUrlParam("clientID");
        RequestCmd cmd = RequestCmd.get(data.getCmd());
        // 无效请求方法，忽略
        if (cmd == null) {
            logger.info("webSocket请求异常: cmd 参数有误，cmd = " + data.getCmd());
            return;
        }
        if (data.getCmd() > 100) {
            gameReq = JSON.parseObject(data.getParam().toString(), GameRoomReq.class);
        } else {
            GroupReq = JSON.parseObject(data.getParam().toString(), GroupChatReq.class);

        }

        /**
         * 首次登陆 根据离线时间 获取离线信息
         */
        if (data.getCmd().equals(RequestCmd.OFFLINE_GROUP_MSG)) {
            groupMsgService.handlerOffLine(Long.valueOf(clientID), client);
            return;
        } else if (data.getCmd().equals(RequestCmd.ONLINE_GROUP_MSG)) {
            // 向当前会话发送信息
            client.sendEvent("message_event", data);
            ConcurrentSkipListMap<String, ClientInfo> groupWithID = groupOnlineMap.get("房间号--待写");
            for (Map.Entry<String, ClientInfo> entry : groupWithID.entrySet()) {
                System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
                if (entry.getValue() != null && entry.getValue().isOnline()) {
                    UUID target = new UUID(entry.getValue().getMostSignificantBits(), entry.getValue().getLeastSignificantBits());
                    logger.info("目标会话UUID:" + target);
                    // 向目标会话发送信息
                    server.getClient(target).sendEvent("message_event", data);
                }
            }
        } else if (data.getCmd().equals(RequestCmd.JOIN_GROUP_CHAT)) {
            if (GroupReq != null) {
                //修改数据库
                groupChatService.insert(GroupReq.getUserID(), GroupReq.getGroupID());
                //更新缓存
                join_group_online(Long.parseLong(clientID), webSocketMap.get(clientID));
                groupChatCache.loadGroupIDByuserID(Long.parseLong(clientID));
                return;
            }
        } else if (data.getCmd().equals(RequestCmd.LEFT_GROUP_CHAT)) {
            if (GroupReq != null) {
                groupChatService.deleteGroupChat(GroupReq.getUserID(), GroupReq.getGroupID());

                left_group_offline(GroupReq.getUserID());
                groupChatCache.loadGroupIDByuserID(GroupReq.getUserID());
            }
        } else if (data.getCmd().equals(RequestCmd.CLOSE_GROUP_CHAT)) {
            if (GroupReq != null) {
                groupClubService.closeGroupClub(GroupReq.getUserID(), GroupReq.getGroupID());
            }
        } else if (data.getCmd().equals(RequestCmd.ROOM_CREATE)) {
            User user = userService.findByUserID(Long.valueOf(clientID));
            if (user.getRoomCard()==0){
                gameResponseDto.setCmd(ErrorCode.USER_ROOMCARD_LIMIT.getCode());
                gameResponseDto.setData("房卡个数不足");
            }
            user.setRoomCard(user.getRoomCard()-1);
            userService.update(user);

            Game game = JSON.parseObject(data.getParam().toString(),Game.class);
            //创建房间
            Room room = gameRoomCache.loadByuserID(Long.parseLong(clientID));
            GameToRoom.copyGameToRoom(game,room);
            gameResponseDto.setCmd(RequestCmd.ROOM_CREATE.getCode());
            gameResponseDto.setData(RoomInfoRsp.Initialization(room));
            client.sendEvent("message_event", gameResponseDto);
            //若是群组创建 还要向群组内发送创建房间信息
            gameRoomCache.updateRoom(room.getShareCode(),room);

            return;
            //
        } else if (data.getCmd().equals(RequestCmd.ROOM_JOIN)) {
            Room room = gameRoomCache.loadByshareCode(gameReq.getShareCode());
            gameResponseDto.setCmd(RequestCmd.ROOM_JOIN.getCode());
            if (room == null || room.getRoomstate() == 0) {
                gameResponseDto.setData("该房间不可加入或已解散");
                client.sendEvent("message_event", gameResponseDto);
                return;
            }
            User user = userService.findByUserID(Long.parseLong(clientID));
            //身份转换成player 添加到等待列表
            Player player = PlayerPoToDtoUtil.copyUserToPlayer(user, client.getSessionId(), room);

            Boolean suc = roomService.inRoom(room,player);
            if (suc==true)
            {
                GameResponseDto gameRsp = new GameResponseDto();
                gameResponseDto.setCmd(RequestCmd.DECLARE_ROOM_JOIN.getCode());
                gameResponseDto.setData("加入房间");
                roomService.sendPlayerToOther(player,room);
                roomService.sendMsgToOne(player,gameRsp);
            }

            //更新缓存
            gameRoomCache.updateRoom(room.getShareCode(), room);
        } else if (data.getCmd().equals(RequestCmd.ROOM_DETAIL)) {
            gameResponseDto.setCmd(RequestCmd.ROOM_DETAIL.getCode());
            gameResponseDto.setData(gameRoomCache.loadByshareCode(gameReq.getShareCode()));
            client.sendEvent("message_event", gameResponseDto);
        } else if (data.getCmd().equals(RequestCmd.GAME_START)){

        }
    }

    private void join_group_online(Long clientID, ClientInfo si) {
        List<GroupChat> groupChatList = groupChatService.listByUserID(Long.valueOf(clientID));
        if (groupChatList != null && groupChatList.size() > 0) {
            for (GroupChat groupChat : groupChatList) {
                ConcurrentSkipListMap<String, ClientInfo> clientInfoHashMap = new ConcurrentSkipListMap<>();
                clientInfoHashMap.put(groupChat.getUserid().toString(), si);
                groupOnlineMap.put(groupChat.getGroupid().toString(), clientInfoHashMap);
            }
        }
    }

    private void left_group_offline(Long clientID) {
        List<Long> groupChatList = groupChatCache.loadByUserID(clientID);
        if (groupChatList != null && groupChatList.size() > 0) {
            for (Long aLong : groupChatList) {
                ConcurrentSkipListMap<String, ClientInfo> skipListMap = groupOnlineMap.get(aLong);
                groupOnlineMap.get(aLong).remove(skipListMap.get(clientID));
            }
        }
    }


}